<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .red {
            color: red;
        }
        
        .green {
            color: green;
        }
    </style>
</head>

<body>
    <div id="app"></div>


    <script>
        function h(tag, props, children) {
            return {
                tag,
                props,
                children
            }
        }

        function mount(vnode, container) {
            const el = vnode.el = document.createElement(vnode.tag)
            if (vnode.props) {
                for (const key in vnode.props) {
                    const value = vnode.props[key];
                    el.setAttribute(key, value)
                }
            }
            if (vnode.children) {
                if (typeof vnode.children === 'string') {
                    el.textContent = vnode.children
                } else {
                    vnode.children.forEach(child => {
                        mount(child, el)
                    });
                }

            }
            container.appendChild(el)
        }

        const vdom = h('div', {
            class: 'red'
        }, [h('span', null, 'hello')])
        mount(vdom, document.getElementById('app'))


        //n1,代表旧的虚拟dom,是之前的快照
        //n2,代表新的需要更新上去的虚拟dom
        function patch(n1, n2) {
            const el = n2.el = n1.el
            if (n1.tag === n2.tag) {
                const oldProps = n1.props || {}
                const newProps = n2.props || {}
                for (const key in newProps) {
                    const oldValue = oldProps[key]
                    const newValue = newProps[key]
                    if (newValue !== oldValue) {
                        el.setAttribute(key, newValue)
                    }
                }
                //考虑到一种情况,当新的el上并没旧元素上的props时,要删除
                for (const key in oldProps) {
                    if (!(key in newProps)) {
                        el.removeAttribute(key)
                    }
                }


                //children
                const oldChildren = n1.children
                const newChildren = n2.children
                if (typeof newChildren === 'string') {
                    if (typeof oldChildren === 'string') {
                        if (newChildren !== oldChildren) {
                            el.textContent = newChildren
                        }
                    } else {
                        el.textContent = newChildren
                    }
                } else {
                    if (typeof oldChildren === 'string') {
                        el.innweHTML = ''
                        newChildren.forEach(child => {
                            mount(child, el)
                        })
                    } else {
                        const commonLength = Math.min(oldChildren.length, newChildren.length)
                        for (let index = 0; index < commonLength; index++) {
                            patch(oldChildren[index], newChildren[index])
                        }
                        if (newChildren.length > oldChildren.length) {
                            newChildren.slice(oldChildren.length).forEach(child => {
                                mount(child, el)
                            })
                        } else if (newChildren.length < oldChildren.length) {
                            oldChildren.slice(newChildren.length).forEach(child => {
                                el.removeChild(child, el)
                            })
                        }
                    }
                }



            } else {
                //replace
            }
        }
        const vdom2 = h('div', {
            class: 'green'
        }, [h('span', null, 'change!')])
        patch(vdom, vdom2)
    </script>
</body>

</html>